home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 June / Macworld (1999-06).dmg / Shareware World / Info / For Developers / MacZoop2.0.sea / MacZoop2.0 / Required Classes / ZWindow.cpp < prev    next >
Text File  |  1999-02-25  |  64KB  |  2,506 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZWindow.cpp            -- the window object
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *            14/11/96- modified to support undo and printing.
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZWindow.h"
  23. #include    "MacZoop.h"
  24. #include    "ZEventHandler.h"
  25. #include    "ZUndoTask.h"
  26. #include    "ProjectSettings.h"
  27.  
  28. #if _INSTALL_STD_MOUSE_TRACKING
  29. #include    "ZMouseTracker.h"
  30. #endif
  31.  
  32. #if APPEARANCE_MGR_AWARE
  33.     #include    "Appearance.h"
  34. #endif
  35.  
  36.  
  37. #if _WPOS_WINDOW_PLACEMENT
  38. #include    "ZResourceFile.h"
  39. #endif
  40.  
  41.  
  42. static short CalculateOffsetAmount(    short idealStartPoint,
  43.                                     short idealEndPoint,
  44.                                     short idealOnScreenStartPoint,
  45.                                     short idealOnScreenEndPoint,
  46.                                     short screenEdge1,
  47.                                     short screenEdge2 );
  48.                                     
  49. static pascal OSErr    ZWTrackingHandler( DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
  50.                                         DragReference theDrag );
  51. static pascal OSErr    ZWDropHandler( WindowPtr theWindow, void* refCon, DragReference theDrag );
  52.  
  53.  
  54.  
  55. static DragTrackingHandlerUPP    gDragTrackProc      = NewDragTrackingHandlerProc( ZWTrackingHandler );
  56. static DragReceiveHandlerUPP    gDragReceiveProc = NewDragReceiveHandlerProc( ZWDropHandler );
  57.  
  58.  
  59. extern OSErr            gDragErr;
  60.  
  61. CLASSCONSTRUCTOR( ZWindow );
  62.  
  63. /*------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  64.  
  65. ZWindow::ZWindow( ZCommander* aBoss, const short windowID )
  66.     : ZCommander( aBoss )
  67. {
  68.     classID = CLASS_ZWindow;
  69.     
  70.     windID = windowID;
  71.     macWindow = NULL;
  72.     dirty = FALSE;
  73.     isNamed = FALSE;
  74.     stationeryFile = FALSE;
  75.     macFile.vRefNum = kNoFile;
  76.     macFType = 0;
  77.     printable = FALSE;
  78.     isPrinting = FALSE;
  79.     floating = FALSE;
  80.     disableAutoClose = FALSE;
  81.     SetRect( &zoomSource, 0, 0, 0, 0 );
  82.     
  83.     // initial sizeRect is set to an arbitrary size
  84.     
  85.     SetRect( &sizeRect,120 ,90 ,2000, 2000 );
  86.     winBackColour.red = winBackColour.green = winBackColour.blue = 0xFFFF;
  87. }
  88.  
  89.  
  90. ZWindow::ZWindow()
  91.     : ZCommander()
  92. {
  93.     classID = CLASS_ZWindow;
  94.  
  95.     windID = 0;
  96.     macWindow = NULL;
  97.     dirty = FALSE;
  98.     isNamed = FALSE;
  99.     stationeryFile = FALSE;
  100.     macFile.vRefNum = kNoFile;
  101.     macFType = 0;
  102.     printable = FALSE;
  103.     isPrinting = FALSE;
  104.     floating = FALSE;
  105.     disableAutoClose = FALSE;
  106.     SetRect( &zoomSource, 0, 0, 0, 0 );
  107.     SetRect( &sizeRect, 0, 0, 0, 0 );
  108.     winBackColour.red = winBackColour.green = winBackColour.blue = 0xFFFF;
  109. }    
  110.  
  111. /*------------------------------***  DESTRUCTOR  ***---------------------------------*/
  112.  
  113. ZWindow::~ZWindow()
  114. {
  115.     // set the current port to something else
  116.     
  117.     if ( FrontWindow())
  118.         SetPort( FrontWindow()); 
  119.     
  120.     // if the application has an undo task pertaining to this window, delete it.
  121.     
  122.     ZUndoTask*    curTask = gApplication->GetUndoTask();
  123.     
  124.     if ( curTask && ( curTask->GetUndoTarget() == this ))
  125.         gApplication->SetTask( NULL );
  126.     
  127.     // wMgr no longer needs us
  128.         
  129.     gWindowManager->RemoveWindow( this );
  130.     
  131.     if ( macWindow )
  132.     {
  133.         #if _AUTO_WPOS_FOR_FLOATERS
  134.         
  135.         if ( floating )
  136.             SavePosition();
  137.         
  138.         #endif
  139.         
  140.         if ( MacHasDM())
  141.             RemoveDragHandlers();
  142.  
  143.         DisposeWindow( macWindow );
  144.     }
  145.     
  146.     macWindow = NULL;
  147. }
  148.  
  149.  
  150. /*--------------------------------***  INITZWINDOW  ***---------------------------------*/
  151. /*    
  152.  
  153. initialise this object. By default, this just makes the window
  154. ----------------------------------------------------------------------------------------*/
  155.  
  156. void    ZWindow::InitZWindow()
  157. {
  158.     MakeMacWindow( windID );
  159.     
  160.     if ( MacHasDM())
  161.         InstallDragHandlers();
  162.  
  163.     // tell the window manager of our existence. This must be done after the
  164.     // full build of the mac window since the window manager needs to get
  165.     // information from it. Thus if you override this method, make sure you
  166.     // make the same call.
  167.     
  168.     gWindowManager->AddWindow( this );
  169.     
  170.     #if _AUTO_WPOS_FOR_FLOATERS
  171.     
  172.     if ( floating )
  173.         RestorePosition();
  174.     
  175.     #endif
  176. }
  177.  
  178.  
  179. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  180. /*    
  181.  
  182. create the macintosh window that this object looks after
  183. ----------------------------------------------------------------------------------------*/
  184.  
  185. void    ZWindow::MakeMacWindow( const short windID )
  186. {
  187.     if ( gMacInfo.supportsColour )
  188.         FailNIL( macWindow = GetNewCWindow( windID, NULL, NULL ));
  189.     else
  190.         FailNIL( macWindow = GetNewWindow( windID, NULL, NULL ));
  191.     
  192.     // store the background colour so we can avoid GetAuxWin, etc.
  193.         
  194.     SetPort( macWindow );
  195.     GetBackColor( &winBackColour );
  196.         
  197.     // so we can identify the window, we set the windowKind to a special value. The refCon
  198.     // contains the object reference so we can freely locate the object from the window and
  199.     // vice versa. Your application must not touch the refCon- add members to your window
  200.     // objects instead.
  201.     
  202.     ((WindowPeek) macWindow)->windowKind = IS_ZWINDOW_KIND;
  203.     SetWRefCon( macWindow, (long) this );
  204.     
  205.     // what WDEF are we using for this window? If it's one of the known "floater" types,
  206.     // then we should set the floating flag automatically- one less thing the programmer
  207.     // needs to worry about, and will work for the common cases.
  208.     
  209.     WindTemplateHdl        wTH = (WindTemplateHdl) GetResource( 'WIND', windID );
  210.     
  211.     if ( wTH )
  212.     {
  213.         // the system floater has a proc of 124. The commonly used "Infinity" windoid
  214.         // has a proc of 128.
  215.         
  216.         short    pID = (*wTH)->procID / 16;
  217.         
  218.         // with appearance manager, the WDEF IDs for floating windows are 66 & 67
  219.         
  220.         #if APPEARANCE_MGR_AWARE
  221.         
  222.         if ( gMacInfo.hasAppearanceMgr )
  223.             floating |= (     pID == kWindowUtilityDefProcResID ||
  224.                             pID == kWindowUtilitySideTitleDefProcResID );
  225.         
  226.         #endif
  227.         
  228.         floating |= (    pID == kFloatingWindowDefinition ||
  229.                         pID == kInfinityWindoidDefinition );
  230.  
  231.         ReleaseResource((Handle) wTH );
  232.     }
  233.     
  234.     // allocate a unique title. This we'll base on the current title
  235.     // (which should be "untitled"), with an appended digit to ensure uniqueness
  236.     
  237.     Str255    wTitle;
  238.     
  239.     GetWTitle( macWindow, wTitle );
  240.     if ( gWindowManager->GetUniqueUntitledName( wTitle ))
  241.         SetWTitle( macWindow, wTitle );
  242.         
  243.     CopyPString( wTitle, macFile.name );
  244.         
  245.     // if appearance savvy, make a root control for the window so stuff can be
  246.     // embedded into it easily.
  247.     
  248.     #if APPEARANCE_MGR_AWARE
  249.     
  250.     if ( gMacInfo.hasAppearanceMgr )
  251.     {
  252.         ControlHandle    rc;
  253.         
  254.         FailOSErr( CreateRootControl( macWindow, &rc ));
  255.     }
  256.     
  257.     #endif
  258. }
  259.  
  260. /*------------------------------***  MAKEMACWINDOW  ***---------------------------------*/
  261.  
  262. void        ZWindow::MakeMacWindow( Rect* aRect, Str255 title, Boolean visible, short varCode, Boolean hasCloseBox, void* userData )
  263. {
  264.     if ( gMacInfo.supportsColour )
  265.         FailNIL( macWindow = NewCWindow( NULL, aRect, title, visible, varCode, NULL, hasCloseBox, 0 ));
  266.     else
  267.         FailNIL( macWindow = NewWindow( NULL, aRect, title, visible, varCode, NULL, hasCloseBox, 0 ));
  268.  
  269.     ((WindowPeek) macWindow)->windowKind = IS_ZWINDOW_KIND;
  270.     SetWRefCon( macWindow, (long) this );
  271.  
  272.     CopyPString( title, macFile.name );
  273.         
  274.     // if appearance savvy, make a root control for the window so stuff can be
  275.     // embedded into it easily.
  276.     
  277.     #if APPEARANCE_MGR_AWARE
  278.     
  279.     if ( gMacInfo.hasAppearanceMgr )
  280.     {
  281.         ControlHandle    rc;
  282.         
  283.         FailOSErr( CreateRootControl( macWindow, &rc ));
  284.     }
  285.     
  286.     #endif
  287. }
  288.  
  289. #pragma mark -
  290.  
  291. /*----------------------------------***  ACTIVATE  ***----------------------------------*/
  292. /*    
  293.  
  294. this window is becoming active
  295. ----------------------------------------------------------------------------------------*/
  296.  
  297. void    ZWindow::Activate()
  298. {
  299.     DrawGrow();
  300. }
  301.  
  302.  
  303. /*---------------------------------***  DEACTIVATE  ***---------------------------------*/
  304. /*    
  305.  
  306. this window is becoming inactive
  307. ----------------------------------------------------------------------------------------*/
  308.  
  309. void    ZWindow::Deactivate()
  310. {
  311.     DrawGrow();
  312. }
  313.  
  314.  
  315. /*------------------------------------***  FOCUS  ***-----------------------------------*/
  316. /*    
  317.  
  318. make this window the current port ready for drawing or clicking
  319. ----------------------------------------------------------------------------------------*/
  320.  
  321. void    ZWindow::Focus()
  322. {
  323.     SetGWorld((CGrafPtr) macWindow, GetMainDevice());
  324.     SetOrigin( 0, 0 );
  325.     ClipRect( &macWindow->portRect );
  326. }
  327.  
  328.  
  329. /*--------------------------------***  POSTREFRESH  ***---------------------------------*/
  330. /*    
  331.  
  332. invalidate the window contents so that it gets redrawn on the next update
  333. ----------------------------------------------------------------------------------------*/
  334.  
  335. void    ZWindow::PostRefresh()
  336. {
  337.     Rect    r;
  338.     
  339.     Focus();
  340.     GetContentRect( &r );
  341.     InvalRect( &r );
  342. }
  343.  
  344.  
  345.  
  346. /*--------------------------------***  POSTREFRESH  ***---------------------------------*/
  347. /*    
  348.  
  349. invalidate the rect passed
  350. ----------------------------------------------------------------------------------------*/
  351.  
  352. void    ZWindow::PostRefresh( Rect* aRect )
  353. {
  354.     Focus();
  355.     InvalRect( aRect );
  356. }
  357.  
  358.  
  359. /*------------------------------***  PERFORMUPDATE  ***---------------------------------*/
  360. /*    
  361.  
  362. handle an update event. This is normally called from the event handler object, but you
  363. can call it directly for special purposes if you know there is an update that needs
  364. handling.
  365. ----------------------------------------------------------------------------------------*/
  366.  
  367. void    ZWindow::PerformUpdate()
  368. {
  369.     GrafPtr        savePort;
  370.     
  371.     GetPort( &savePort );
  372.     Focus();
  373.     
  374.     // start the update sequence
  375.     
  376.     BeginUpdate( macWindow );
  377.     
  378.     if ( ! EmptyRgn( macWindow->visRgn ))
  379.     {
  380.         try
  381.         {
  382.             Draw();
  383.         }
  384.         catch( OSErr err )
  385.         {
  386.             EndUpdate( macWindow );
  387.             SetPort( savePort );
  388.             throw err;
  389.         }
  390.     }
  391.     EndUpdate( macWindow );
  392.     SetPort( savePort );
  393. }
  394.  
  395. /*------------------------------------***  DRAW  ***------------------------------------*/
  396. /*    
  397.  
  398. draw the contents of this window. This is the main draw dispatcher.
  399. ----------------------------------------------------------------------------------------*/
  400.  
  401. void    ZWindow::Draw()
  402. {
  403.     // if we are growable, we should clip out the growbox area otherwise
  404.     // the DrawContent call may erase the growbox, etc
  405.     
  406.     short    v = GetWVariant(macWindow);
  407.     
  408.     if (v == documentProc || v == zoomDocProc)
  409.     {
  410.         Rect    r = macWindow->portRect;
  411.         
  412.         ClipRect( &r );
  413.         
  414.         r.left = r.right - kStdScrollbarWidth;
  415.         r.top = r.bottom - kStdScrollbarWidth;
  416.         
  417.         RectRgn( gUtilRgn, &r );
  418.         DiffRgn( macWindow->clipRgn, gUtilRgn, macWindow->clipRgn );
  419.     }
  420.     
  421.     DrawContent();
  422.     
  423.     SetOrigin( 0, 0 );
  424.     ClipRect( &macWindow->portRect );        
  425.     DrawControls( macWindow );
  426.  
  427.     DrawGrow();
  428. }
  429.  
  430.  
  431. /*-------------------------------***  DRAWCONTENT  ***----------------------------------*/
  432. /*    
  433.  
  434. draw the content area of this window- this is what will draw the meaningful part
  435. ----------------------------------------------------------------------------------------*/
  436.  
  437. void    ZWindow::DrawContent()
  438. {
  439.     if (! isPrinting)
  440.         EraseRect( &macWindow->portRect );
  441. }
  442.  
  443.  
  444. /*----------------------------***  SETDEFAULTCOLOURS  ***-------------------------------*/
  445. /*    
  446. restores the window's default colours after drawing code may have changed it.
  447. ----------------------------------------------------------------------------------------*/
  448.  
  449. void    ZWindow::SetDefaultColours()
  450. {
  451.     Focus();
  452.     ForeColor( blackColor );
  453.     
  454.     if ( IsColourPort( macWindow ))
  455.         RGBBackColor( &winBackColour );
  456.     else
  457.         BackColor( whiteColor );
  458. }    
  459.  
  460. /*---------------------------------***  DRAWGROW  ***-----------------------------------*/
  461. /*    
  462.  
  463. draw the grow icon if the window type indicates this is appropriate
  464. ----------------------------------------------------------------------------------------*/
  465.  
  466. void    ZWindow::DrawGrow()
  467. {
  468.     if ( macWindow )
  469.     {
  470.         short    v = GetWVariant( macWindow );
  471.         
  472.         if ( v == documentProc || v == zoomDocProc )
  473.         {
  474.             Rect    r = macWindow->portRect;
  475.             
  476.             r.left = r.right - kStdScrollbarWidth;
  477.             r.top = r.bottom - kStdScrollbarWidth;
  478.             
  479.             ClipRect( &r );
  480.             DrawGrowIcon( macWindow );
  481.         }
  482.     }
  483. }
  484.  
  485.  
  486. #pragma mark -
  487.  
  488. /*---------------------------------***  CALCPAGES  ***----------------------------------*/
  489. /*    
  490.  
  491. compute the pagination for printing. By default this divides the contect rect up to be
  492. tiled across the paper rect, horizontal major order. Override for other methods
  493. ----------------------------------------------------------------------------------------*/
  494.  
  495. void    ZWindow::CalcPages( const Rect& paperRect, short* pagesH, short* pagesV )
  496. {
  497.     Rect    cr;
  498.     short    pWidth, pHeight, cWidth, cHeight;
  499.     
  500.     GetBounds( &cr );
  501.     
  502.     pWidth = paperRect.right - paperRect.left;
  503.     pHeight = paperRect.bottom - paperRect.top;
  504.     
  505.     cWidth = cr.right - cr.left;
  506.     cHeight = cr.bottom - cr.top;
  507.     
  508.     *pagesH = (cWidth / pWidth) + 1;
  509.     *pagesV = (cHeight / pHeight) + 1;
  510. }
  511.  
  512. /*-------------------------------***  PRINTONEPAGE  ***---------------------------------*/
  513. /*    
  514. draw the requested page (numbered according to the pagination you set up) to the current
  515. port, which will be a printing port when called. By default this manipulates the origin
  516. and draws the content, suitably clipped, to the port. Override for other behaviour.
  517. ----------------------------------------------------------------------------------------*/
  518.  
  519. void    ZWindow::PrintOnePage( const short pageNum, const Rect& paperRect )
  520. {
  521.     Rect    pr;
  522.     short    hp, vp, dH, dV;
  523.     
  524.     // calculate the printing area
  525.     
  526.     CalcPages( paperRect, &hp, &vp );
  527.     pr = paperRect;
  528.     
  529.     dH = paperRect.right  * ((pageNum - 1) % hp);
  530.     dV = paperRect.bottom * ((pageNum - 1) / hp);
  531.     
  532.     OffsetRect( &pr, dH, dV );
  533.     
  534.     // make sure that the text & pen attributes in the window and printing port match
  535.     // in case the DrawContent routine doesn't set them as it goes.
  536.     
  537.     TextFont( macWindow->txFont );
  538.     TextSize( macWindow->txSize );
  539.     TextFace( macWindow->txFace );
  540.     TextMode( srcOr );
  541.     PenSize( macWindow->pnSize.h, macWindow->pnSize.v );
  542.     PenPat( &macWindow->pnPat );
  543.     PenMode( macWindow->pnMode );
  544.     
  545.     // draw the contents.
  546.     
  547.     SetOrigin( pr.left, pr.top );
  548.     ClipRect( &pr );
  549.     
  550.     DrawContent();
  551.     SetOrigin( 0, 0 );
  552. }
  553.  
  554.  
  555. /*------------------------------***  GETCONTENTRECT  ***--------------------------------*/
  556. /*    
  557.  
  558. return the content area
  559. ----------------------------------------------------------------------------------------*/
  560.  
  561. void    ZWindow::GetContentRect( Rect* contents )
  562. {
  563.     *contents = macWindow->portRect;
  564. }
  565.  
  566.  
  567.  
  568. /*-----------------------------------***  CLICK  ***------------------------------------*/
  569. /*    
  570.  
  571. the user clicked in the content area of this window. By default this does simple tracking.
  572. ----------------------------------------------------------------------------------------*/
  573.  
  574. void    ZWindow::Click( const Point mouse, const short modifiers )
  575. {
  576. #if _INSTALL_STD_MOUSE_TRACKING
  577.     if ( ! Floats())
  578.     {
  579.         ZMouseTracker    mt( this );
  580.     
  581.         mt.Track( mouse );
  582.     }
  583. #endif
  584. }
  585.  
  586.  
  587. /*-----------------------------***  CLICKINSAMEPLACE  ***-------------------------------*/
  588. /*    
  589.  
  590. should this click be considered a double-click? You can override this and return TRUE if
  591. the two points are to be considered in the same place for the purposes of determining
  592. a double-click. The default method always returns TRUE. The points passed are in the
  593. window's LOCAL coordinates.
  594.  
  595. ----------------------------------------------------------------------------------------*/
  596.  
  597. Boolean    ZWindow::ClickInSamePlace( const Point click1, const Point click2 )
  598. {
  599.     return TRUE;
  600. }
  601.  
  602.  
  603. /*-------------------------------***  ADJUSTCURSOR  ***---------------------------------*/
  604. /*    
  605.  The cursor is over this window. Set its shape according to where it is and what modifiers
  606.  are down. By default this just sets the cursor to an arrow. <mouse> is in local coords.
  607.  
  608. ----------------------------------------------------------------------------------------*/
  609.  
  610. void    ZWindow::AdjustCursor( const Point mouse, const short modifiers )
  611. {
  612.     ResumeCursorAnimation();
  613.     SetCursorShape( ARROW_CURSOR );
  614. }
  615.  
  616.  
  617. /*-------------------------------***  SETSIZERECT  ***----------------------------------*/
  618. /*    
  619.  
  620. set minimum and maximum sizes for this window
  621. ----------------------------------------------------------------------------------------*/
  622.  
  623. void    ZWindow::SetSizeRect( const Rect& szRect )
  624. {
  625.     sizeRect = szRect;
  626.     
  627.     // make sure max is not less than min:
  628.     
  629.     sizeRect.right = MAX( sizeRect.right, sizeRect.left );
  630.     sizeRect.bottom = MAX( sizeRect.bottom, sizeRect.top );
  631.     
  632.     // if the window does not conform to the size constraints, change its size so
  633.     // that it does.
  634.     
  635.     Rect        pr;
  636.     
  637.     pr = macWindow->portRect;
  638.     
  639.     if (( pr.right - pr.left ) < sizeRect.left     ||
  640.         ( pr.right - pr.left ) > sizeRect.right ||
  641.         ( pr.bottom - pr.top ) < sizeRect.top     ||
  642.         ( pr.bottom - pr.top ) > sizeRect.bottom )
  643.         SetSize( pr.right - pr.left, pr.bottom - pr.top, FALSE );
  644. }
  645.  
  646.  
  647. /*-------------------------------***  GETSIZERECT  ***----------------------------------*/
  648. /*    
  649.  
  650. get minimum and maximum sizes for this window
  651. ----------------------------------------------------------------------------------------*/
  652.  
  653. void    ZWindow::GetSizeRect( Rect* szRect )
  654. {
  655.     *szRect = sizeRect;
  656. }
  657.  
  658.  
  659. /*----------------------------------***  CLOSE  ***-------------------------------------*/
  660. /*    
  661.  
  662. we want to close this window. If it needs to be saved, do that. The user may cancel this.
  663. ----------------------------------------------------------------------------------------*/
  664.  
  665. Boolean    ZWindow::Close( const short phase )
  666. {
  667.     // the user wants to close the window. This checks the dirty flag and if dirty, asks the
  668.     // user if they want to save changes, if so, this calls save.
  669.     
  670.     // first see if we have any subsidiary windows and ask them to close
  671.     
  672.     if (! CloseSubsidiaryWindows( phase ))
  673.         return FALSE;
  674.     
  675.     // they were all closed successfully, now check this one
  676.     
  677.     short check = kCloseNoSave;
  678.     
  679.     if ( dirty )
  680.     {
  681.         // we are about to show the "Save Changes?" alert- so make sure we are frontmost and
  682.         // fully updated. This also ensures that a window that is hidden will be correctly
  683.         // reshown under this situation, but not otherwise.
  684.         
  685.         Select();
  686.         PerformUpdate();
  687.         
  688.     #if _USE_NAV_SAVEREVERT_ALERTS
  689.         if ( gMacInfo.hasNavigationServices )
  690.         {
  691.             // use nav services version of the "save changes" dialog:
  692.             
  693.             NavDialogOptions            navOptions;
  694.             NavAskSaveChangesResult        navResult;
  695.             NavAskSaveChangesAction        navAction;
  696.             
  697.             FailOSErr( NavGetDefaultDialogOptions( &navOptions ));
  698.             
  699.             gApplication->GetName( navOptions.clientName );
  700.             GetName( navOptions.savedFileName );
  701.             
  702.             navAction = (phase == kQuitting)? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
  703.             
  704.             FailOSErr( NavAskSaveChanges(    &navOptions,
  705.                                             navAction,
  706.                                             &navResult,
  707.                                             gNavEventHandler,
  708.                                             (NavCallBackUserData) this ));
  709.                                             
  710.             // convert nav result back to MacZoop constants:
  711.             
  712.             switch ( navResult )
  713.             {
  714.                 case kNavAskSaveChangesSave:
  715.                     check = kConfirmSave;
  716.                     break;
  717.                     
  718.                 case kNavAskSaveChangesCancel:
  719.                     check = kCloseCancel;
  720.                     break;
  721.                     
  722.                 case kNavAskSaveChangesDontSave:
  723.                     check = kCloseNoSave;
  724.                     break;
  725.             }
  726.         }
  727.         else
  728.         {
  729.     #endif
  730.         
  731.         Str31    nameStr;
  732.         Str31    phaseStr;
  733.         
  734.         GetName( nameStr );
  735.         GetIndString( phaseStr, kMiscStrListID, ( phase == kRunning )? 1 : 2);
  736.         ParamText( nameStr, phaseStr, NULL, NULL );
  737.         
  738.         SetCursorShape( 0 );
  739.         check = NotifyAlert( kConfirmSaveAlertID );        // do you wish to save?
  740.         
  741.     #if _USE_NAV_SAVEREVERT_ALERTS
  742.         }
  743.     #endif
  744.         
  745.         if ( check == kConfirmSave )
  746.             if (! Save( FALSE ))                        // if so, save the file
  747.                 check = kCloseCancel;
  748.     }
  749.     
  750.     if ( check != kCloseCancel )
  751.     {
  752.         Hide();
  753.         
  754.         SendMessage( kMsgWindowClosing, NULL );        // tell interested parties we're going away
  755.         
  756.         ForgetThis();
  757.         return TRUE;    // was closed
  758.     }
  759.     else
  760.         return FALSE;    // wasn't closed
  761. }
  762.  
  763.  
  764. /*---------------------------***  CLOSESUBSIDIARYWINDOWS  ***---------------------------*/
  765. /*    
  766. ask any windows supervised by this one to close
  767. ----------------------------------------------------------------------------------------*/
  768.  
  769. Boolean    ZWindow::CloseSubsidiaryWindows( const short phase )
  770. {
  771.     Boolean      allClosed = TRUE;
  772.     
  773.     if ( itsUnderlings )
  774.     {
  775.         // there are some commanders supervised by this object. If they are
  776.         // window objects, call their close method
  777.         
  778.         ZWindow*    w;
  779.         long        i = itsUnderlings->CountItems();
  780.         
  781.         while( i )
  782.         {
  783.             // use RTTI to make sure the object is some sort of window
  784.             
  785.             w = dynamic_cast<ZWindow*>(itsUnderlings->GetObject( i-- ));
  786.             
  787.             if (w)
  788.             {
  789.                 // yes it is, so ask it to close
  790.                 
  791.                 if (! w->Close( phase ))
  792.                 {
  793.                     // if it didn't close, then abandon the closure sequence
  794.                     
  795.                     allClosed = FALSE;
  796.                     break;
  797.                 }
  798.             }
  799.         }
  800.     }
  801.     
  802.     return allClosed;
  803. }
  804.  
  805.  
  806. /*--------------------------------***  SENDBEHIND  ***----------------------------------*/
  807. /*    
  808.  
  809. sends this window behind <aWindow> (or behind all if NULL).
  810.  
  811. ----------------------------------------------------------------------------------------*/
  812.  
  813. void    ZWindow::SendBehind( ZWindow* aWindow )
  814. {
  815.     gWindowManager->MoveWindowBehind( this, aWindow );    
  816. }
  817.  
  818.  
  819. /*-----------------------------------***  HIDE  ***-------------------------------------*/
  820. /*    
  821.  
  822. make this window invisible
  823.  
  824. ----------------------------------------------------------------------------------------*/
  825.  
  826. void    ZWindow::Hide()
  827. {
  828.     Boolean wasVis = IsVisible();
  829.     
  830.     gWindowManager->HideWindow( this );
  831.     
  832.     if ( wasVis )
  833.         gWindowManager->ZoomWindowClosed( this );
  834. }
  835.  
  836.  
  837. /*-----------------------------------***  SHOW  ***-------------------------------------*/
  838. /*    
  839.  
  840. make this window visible
  841.  
  842. ----------------------------------------------------------------------------------------*/
  843.  
  844. void    ZWindow::Show()
  845. {
  846.     gWindowManager->ShowWindow( this );
  847. }
  848.  
  849.  
  850. /*---------------------------------***  SELECT  ***-------------------------------------*/
  851. /*    
  852.  
  853. make this window the active window
  854.  
  855. ----------------------------------------------------------------------------------------*/
  856.  
  857. void    ZWindow::Select()
  858. {
  859.     Boolean        wasVis = IsVisible();
  860.     
  861.     gWindowManager->SelectWindow( this );
  862.     
  863.     if ( ! wasVis )
  864.         PerformUpdate();
  865. }
  866.  
  867.  
  868. /*---------------------------------***  PLACEAT  ***------------------------------------*/
  869. /*    
  870.  
  871. position the window on the screen at h, v.
  872.  
  873. ----------------------------------------------------------------------------------------*/
  874.  
  875. void    ZWindow::PlaceAt( const short hGlobal, const short vGlobal )
  876. {
  877.     MoveWindow( macWindow, hGlobal, vGlobal, FALSE );
  878. }
  879.  
  880.  
  881. /*----------------------------------***  PLACE  ***-------------------------------------*/
  882. /*    
  883.  
  884. place the window in it's default location. By default this just calls the window manager's
  885. InitiallyPlace() method. Override it for special placement.
  886. ----------------------------------------------------------------------------------------*/
  887.  
  888. void    ZWindow::Place()
  889. {
  890.     gWindowManager->InitiallyPlace( this );
  891.     
  892.     if ( macFile.vRefNum != kNoFile && ! IsVisible())
  893.         RestorePosition();
  894. }
  895.  
  896.  
  897.  
  898. /*------------------------------***  PLACERELATIVE  ***---------------------------------*/
  899. /*    
  900.  
  901. place the window relative to another window or the screen
  902. ----------------------------------------------------------------------------------------*/
  903.  
  904. void    ZWindow::PlaceRelative( ZWindow* relWindow, WindowPlacing aPlacing )
  905. {
  906.     short        h, v, hh, vv;
  907.     short        ww, wh, sw, sh;
  908.     GDHandle    sDev;
  909.     
  910.     GetContentRegion( gUtilRgn );
  911.     
  912.     ww = (*gUtilRgn)->rgnBBox.right - (*gUtilRgn)->rgnBBox.left;
  913.     wh = (*gUtilRgn)->rgnBBox.bottom - (*gUtilRgn)->rgnBBox.top;
  914.     
  915.     if ( relWindow && ( aPlacing == kCentreOnParent ||
  916.                         aPlacing == kAlertPositionOnParent ||
  917.                         aPlacing == kStaggerOnParent ))
  918.     {
  919.         relWindow->GetContentRegion( gUtilRgn );
  920.         
  921.         sw = (*gUtilRgn)->rgnBBox.right - (*gUtilRgn)->rgnBBox.left;
  922.         sh = (*gUtilRgn)->rgnBBox.bottom - (*gUtilRgn)->rgnBBox.top;
  923.         hh = (*gUtilRgn)->rgnBBox.left;
  924.         vv = (*gUtilRgn)->rgnBBox.top;
  925.     }
  926.     else
  927.     {
  928.         sDev = GetMainDevice();
  929.         
  930.         sw = (*sDev)->gdRect.right;
  931.         sh = (*sDev)->gdRect.bottom;
  932.         hh = vv = 0;    
  933.     }
  934.     
  935.     if ( aPlacing == kStaggerOnParent )
  936.     {
  937.         h = hh + 10;
  938.         v = vv + 20;
  939.     }
  940.     else
  941.     {
  942.         // centre on something
  943.         
  944.         h = hh + ( sw / 2 ) - ( ww / 2 );
  945.         
  946.         if ( aPlacing == kAlertPositionOnParent ||
  947.              aPlacing == kAlertPositionOnScreen )
  948.             v = vv + ( sh / 3 ) - ( wh / 2 );
  949.         else
  950.             v = vv + ( sh / 2 ) - ( wh / 2 );
  951.     }
  952.     
  953.     PlaceAt( h, v );
  954. }
  955.  
  956.  
  957.  
  958. /*-------------------------------***  SAVEPOSITION  ***---------------------------------*/
  959. /*    
  960. save the window's position in a 'Wpos' resource. If the window has a file, it's saved
  961. there. If not, the global prefs file (if any) is used. If the id passed is 0, the windID
  962. is used as a resource ID.
  963. ----------------------------------------------------------------------------------------*/
  964.  
  965. void    ZWindow::SavePosition( short id )
  966. {
  967. #if _WPOS_WINDOW_PLACEMENT
  968.  
  969.     if ( id == 0 )
  970.         id = windID;
  971.         
  972.     ZResourceFile*    aFile = NULL;
  973.     
  974.     if ( macFile.vRefNum != kNoFile )
  975.         FailNIL( aFile = new ZResourceFile( macFile ));
  976.         
  977.     gWindowManager->SaveWindowPosition( this, aFile, id );
  978.  
  979.     if ( aFile )
  980.         ForgetObject( aFile );
  981.         
  982. #endif
  983. }
  984.  
  985.  
  986.  
  987.  
  988. /*-----------------------------***  RESTOREPOSITION  ***--------------------------------*/
  989. /*
  990.  
  991. restores the window's position from a 'WPos' resource, either in its own file or the
  992. prefs, if any. If id is 0, the windID is used to identify the resource.    
  993. ----------------------------------------------------------------------------------------*/
  994.  
  995. void    ZWindow::RestorePosition( short id )
  996. {
  997. #if _WPOS_WINDOW_PLACEMENT
  998.  
  999.     if ( id == 0 )
  1000.         id = windID;
  1001.         
  1002.     ZResourceFile*    aFile = NULL;
  1003.     
  1004.     if ( macFile.vRefNum != kNoFile )
  1005.         FailNIL( aFile = new ZResourceFile( macFile ));
  1006.     
  1007.     gWindowManager->RestoreWindowPosition( this, aFile, id );
  1008.     
  1009.     if ( aFile )
  1010.         ForgetObject( aFile );    
  1011.         
  1012. #endif
  1013. }
  1014.  
  1015.  
  1016. #pragma mark -
  1017.  
  1018. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  1019. /*    
  1020.  
  1021. handle commands for a window, like Save, Save As, Close, etc.
  1022.  
  1023. ----------------------------------------------------------------------------------------*/
  1024.  
  1025. void    ZWindow::HandleCommand( const long aCmd )
  1026. {
  1027.     EventRecord        ev;
  1028.     
  1029.     switch ( aCmd )
  1030.     {
  1031.         case kCmdClose:
  1032.             gApplication->GetCurrentEvent( &ev );
  1033.             
  1034.             if ( ev.modifiers & optionKey )
  1035.                 gApplication->CloseAll( Floats());
  1036.             else
  1037.                 Close( kRunning );
  1038.             break;
  1039.         
  1040.         case kCmdSave:
  1041.             Save( FALSE );
  1042.             break;
  1043.         
  1044.         case kCmdSaveAs:
  1045.             Save( TRUE );
  1046.             break;
  1047.         
  1048.         case kCmdRevert:
  1049.             Revert();
  1050.             break;
  1051.         
  1052.         default:
  1053.             // pass other commands up to this object's boss
  1054.             
  1055.             ZCommander::HandleCommand( aCmd );
  1056.             break;
  1057.     }
  1058. }
  1059.  
  1060.  
  1061. /*------------------------------***  HANDLECOMMAND  ***---------------------------------*/
  1062.  
  1063. void    ZWindow::HandleCommand( const short menuID, const short itemID )
  1064. {
  1065.     ZCommander::HandleCommand( menuID, itemID );
  1066. }
  1067.  
  1068.  
  1069. /*--------------------------------***  UPDATEMENUS  ***---------------------------------*/
  1070. /*    
  1071.  
  1072. update the menus for a window, like Save, Save As, Close, etc.
  1073.  
  1074. ----------------------------------------------------------------------------------------*/
  1075.  
  1076. void    ZWindow::UpdateMenus()
  1077. {
  1078.     // this enables the Close, Save and SaveAs commands.
  1079.     
  1080.     EventRecord        ev;
  1081.     
  1082.     gApplication->GetCurrentEvent( &ev );
  1083.     
  1084.     // show "Close All" if the option key is down, else "Close"
  1085.     
  1086.     if (ev.modifiers & optionKey )
  1087.         gMenuBar->SetCommandText( kCmdClose, kMiscStrListID, 8 );
  1088.     else
  1089.         gMenuBar->SetCommandText( kCmdClose, kMiscStrListID, 9 );
  1090.     
  1091.     gMenuBar->EnableCommand( kCmdClose );
  1092.     
  1093.     if ( dirty )
  1094.     {
  1095.         gMenuBar->EnableCommand( kCmdSave );
  1096.         
  1097.         if ( isNamed )
  1098.             gMenuBar->EnableCommand( kCmdRevert );
  1099.     }
  1100.     gMenuBar->EnableCommand( kCmdSaveAs );
  1101.  
  1102.     // call the boss to enable her menus
  1103.     
  1104.     ZCommander::UpdateMenus();
  1105. }
  1106.  
  1107.  
  1108. /*-----------------------------------***  SETTASK  ***----------------------------------*/
  1109. /*    
  1110. submit an undoable task for this window. This updates the global undo task and marks the
  1111. document as dirty.
  1112. ----------------------------------------------------------------------------------------*/
  1113.  
  1114. void        ZWindow::SetTask( ZUndoTask* aTask )
  1115. {
  1116.     // if we're not dirty when the task arrives, then this must be the first task. Let it
  1117.     // know so that if the task is undone, it can clear the dirty flag so that undoing the
  1118.     // first task doesn't result in the "save changes?" alert.
  1119.     
  1120.     if ( ! dirty && aTask )
  1121.         aTask->SetIsFirstTask();
  1122.     
  1123.     dirty = TRUE;    // document has been changed by the task
  1124.     
  1125.     gApplication->SetTask( aTask );    
  1126. }
  1127.  
  1128.  
  1129. /*---------------------------------***  SETSIZE  ***------------------------------------*/
  1130. /*    
  1131.  
  1132. set this window to the width and height passed
  1133. ----------------------------------------------------------------------------------------*/
  1134.  
  1135. void    ZWindow::SetSize( const short width, const short height, const Boolean reDraw )
  1136. {
  1137.     // sets the window's size to the width and height passed, constrained to sizeRect.
  1138.     
  1139.     short    w, h;
  1140.     
  1141.     w  = MIN( sizeRect.right,  MAX( width, sizeRect.left ));
  1142.     h  = MIN( sizeRect.bottom, MAX( height, sizeRect.top ));
  1143.  
  1144.     if (( w != macWindow->portRect.right - macWindow->portRect.left ) ||
  1145.         ( h != macWindow->portRect.bottom - macWindow->portRect.top ))
  1146.     {
  1147.         Focus();
  1148.         if ( reDraw )
  1149.             EraseRect( &macWindow->portRect );
  1150.         
  1151.         SizeWindow( macWindow, w, h, reDraw );
  1152.         WindowResized();
  1153.         
  1154.         if ( reDraw )
  1155.             Draw();
  1156.     }
  1157. }
  1158.  
  1159.  
  1160. /*-----------------------------------***  ZOOM  ***-------------------------------------*/
  1161. /*    
  1162.  
  1163. Zoom this window between the standard and user states. This implements intelligent zoom-
  1164. ing as recommended by the Apple HIG people. It may appear complex and indeed it probably
  1165. is, however, the results are worth it since the zooming of windows almost always does
  1166. exactly the most correct thing for your data- automatically! It also deals with any number
  1167. of multiple monitors. You can always override this if you want something different.
  1168. Based largely on code by Dean Yu, Apple Computer Inc.
  1169. ----------------------------------------------------------------------------------------*/
  1170.  
  1171. #define        kNudgeSlop                2
  1172. #define        kIconAllowance            64
  1173. #define        kTabFolderAllowance        20
  1174.  
  1175.  
  1176. void    ZWindow::Zoom( const short partCode )
  1177. {
  1178.     RgnHandle    contRgn, strucRgn, scratchRgn;
  1179.     Rect        portRect, crBBox, srBBox, zwBounds, wpOnScreen;
  1180.     short        wfTop, wfLeft, wfBottom, wfRight;
  1181.     long        largestArea = 0;
  1182.     GDHandle    aScreen, targetMonitor;
  1183.     
  1184.     Focus();
  1185.     EraseRect( &macWindow->portRect );
  1186.     
  1187.     // calculate the most intelligent zoom state for the window and set the
  1188.     // standard state to it. The most intelligent state is on the monitor with
  1189.     // the largest area of the window, and that involves the minimum amount of
  1190.     // window movement.
  1191.     
  1192.     if ( partCode == inZoomOut )
  1193.     {
  1194.         GetContentRegion( contRgn = NewRgn());
  1195.         GetStructureRegion( strucRgn = NewRgn());
  1196.         portRect = macWindow->portRect;
  1197.         crBBox = (*contRgn)->rgnBBox;
  1198.         srBBox = (*strucRgn)->rgnBBox;
  1199.         
  1200.         // calculate the window frame size
  1201.         
  1202.         wfTop        = crBBox.top     - srBBox.top;
  1203.         wfLeft        = crBBox.left     - srBBox.left;
  1204.         wfBottom     = srBBox.bottom - crBBox.bottom;
  1205.         wfRight     = srBBox.right     - crBBox.right;
  1206.         
  1207.         // the ideal size for this window is the max sizeRect. For scrollable windows,
  1208.         // this is set according to the bounds, which will give us the expected results
  1209.         // we now need to find the monitor that has the largest portion of the window
  1210.         // intersecting it.
  1211.         
  1212.         scratchRgn = NewRgn();
  1213.         SectRgn( GetGrayRgn(), contRgn, scratchRgn );
  1214.         if (EmptyRgn( scratchRgn ))
  1215.             zwBounds = srBBox;
  1216.         else
  1217.             zwBounds = crBBox;
  1218.         DisposeRgn( scratchRgn );
  1219.         
  1220.         // re-use srBBox for the new standard state rect, initially set to the ideal
  1221.         // window size if we had an infinitely large monitor.
  1222.         
  1223.         GetIdealWindowZoomSize( &srBBox );
  1224.         
  1225.         // walk the device list to determine which monitor the window should be
  1226.         // zoomed to:
  1227.         
  1228.         aScreen = GetDeviceList();
  1229.         
  1230.         while (aScreen)
  1231.         {
  1232.             long wpArea;
  1233.             // find the intersection of the window and the screen
  1234.             
  1235.             SectRect( &zwBounds, &(*aScreen)->gdRect, &wpOnScreen );
  1236.             
  1237.             // find the area of this portion
  1238.             
  1239.             OffsetRect( &wpOnScreen, -wpOnScreen.left, -wpOnScreen.top );
  1240.             wpArea = (long) wpOnScreen.right * (long) wpOnScreen.bottom;
  1241.             
  1242.             // if this is larger than the area found so far, keep track of
  1243.             // the monitor that contains it
  1244.             
  1245.             if (wpArea > largestArea)
  1246.             {
  1247.                 largestArea = wpArea;
  1248.                 targetMonitor = aScreen;
  1249.             }
  1250.             // look at the next monitor in the list
  1251.             
  1252.             aScreen = GetNextDevice( aScreen );
  1253.         }
  1254.         
  1255.         // ok, we have found the monitor we wish to zoom to. Store the monitor's
  1256.         // global rect in the wpOnScreen variable
  1257.         
  1258.         wpOnScreen = (*targetMonitor)->gdRect;
  1259.         
  1260.         // allow for the menubar and desktop icons if it's the main one
  1261.         
  1262.         if (targetMonitor == GetMainDevice())
  1263.         {
  1264.             wpOnScreen.top += GetMBarHeight();
  1265.             wpOnScreen.right -= kIconAllowance;
  1266.             
  1267.             // if we have tabbed folders (8.x), allow space for it
  1268.             
  1269.             if ( gMacInfo.systemVersion >= 0x0800 )
  1270.                 wpOnScreen.bottom -= kTabFolderAllowance;
  1271.         }
  1272.             
  1273.         // OK, we can now calculate the standard rect we wish to zoom to (finally).
  1274.         // We calculate this using srBBox, since that now holds the new std state
  1275.         
  1276.         OffsetRect( &srBBox, crBBox.left, crBBox.top );
  1277.         srBBox.top       -= wfTop;
  1278.         srBBox.left   -= wfLeft;
  1279.         srBBox.right  += wfRight;
  1280.         srBBox.bottom += wfBottom;
  1281.         
  1282.         // this is the ideal size for the window content. See if it needs nudging onto the
  1283.         // monitor
  1284.         
  1285.         SectRect( &srBBox, &wpOnScreen, &zwBounds );
  1286.         if (! EqualRect( &srBBox, &zwBounds ))
  1287.         {
  1288.             // needs to be nudged onto the monitor.
  1289.             
  1290.             short    oH, oV;
  1291.             
  1292.             oH = CalculateOffsetAmount( srBBox.left, srBBox.right,
  1293.                                         zwBounds.left, zwBounds.right,
  1294.                                         wpOnScreen.left, wpOnScreen.right );
  1295.             oV = CalculateOffsetAmount( srBBox.top, srBBox.bottom,
  1296.                                         zwBounds.top, zwBounds.bottom,
  1297.                                         wpOnScreen.top, wpOnScreen.bottom );
  1298.             OffsetRect( &srBBox, oH, oV );
  1299.         }
  1300.         
  1301.         // If this still falls off the screen in any direction, it means that it is too large
  1302.         // for the montior, so it will need to be shrunk down to fit.
  1303.         
  1304.         SectRect( &srBBox, &wpOnScreen, &zwBounds);
  1305.         if (! EqualRect( &srBBox, &zwBounds ))
  1306.         {
  1307.             // nope- still doesn't fit. So shrink it down.
  1308.             
  1309.             if ((srBBox.right - srBBox.left) > (wpOnScreen.right - wpOnScreen.left))
  1310.             {
  1311.                 srBBox.left = wpOnScreen.left + kNudgeSlop;
  1312.                 srBBox.right = wpOnScreen.right - kNudgeSlop;
  1313.             }
  1314.             
  1315.             if ((srBBox.bottom - srBBox.top) > (wpOnScreen.bottom - wpOnScreen.top))
  1316.             {
  1317.                 srBBox.top = wpOnScreen.top + kNudgeSlop;
  1318.                 srBBox.bottom = wpOnScreen.bottom - kNudgeSlop;
  1319.             }
  1320.         }
  1321.         
  1322.         // adjust for the thickness of the frame and set the standard rect
  1323.         
  1324.         srBBox.top       += wfTop;
  1325.         srBBox.left   += wfLeft;
  1326.         srBBox.right  -= wfRight;
  1327.         srBBox.bottom -= wfBottom;
  1328.         
  1329.         SetStdZoomRect( srBBox );
  1330.         
  1331.         DisposeRgn( contRgn );
  1332.         DisposeRgn( strucRgn );
  1333.     }
  1334.     // and.... Zoom!
  1335.  
  1336.     ZoomWindow( macWindow, partCode, FALSE );
  1337.     
  1338.     // notify resize of window
  1339.     
  1340.     WindowResized();
  1341. }
  1342.  
  1343.  
  1344. /*--------------------------***  GETIDEALWINDOWZOOMSIZE  ***----------------------------*/
  1345. /*    
  1346. return the optimum ideal size for a zoomed window. By default this is equal to the
  1347. max size rectangle, but you can override this if you know better.
  1348. ----------------------------------------------------------------------------------------*/
  1349.  
  1350. void    ZWindow::GetIdealWindowZoomSize( Rect* idealSize )
  1351. {
  1352.     idealSize->top = idealSize->left = 0;
  1353.     idealSize->right = sizeRect.right;
  1354.     idealSize->bottom = sizeRect.bottom;    
  1355. }
  1356.  
  1357.  
  1358. /*------------------------------***  SETSTDZOOMRECT  ***--------------------------------*/
  1359. /*    
  1360. set the std rect for zoomable windows. The window zooms to this rect when the zoom box
  1361. is clicked. If the window is not zoomable, this does nothing. The rect is in global coords.
  1362. ----------------------------------------------------------------------------------------*/
  1363.  
  1364. void    ZWindow::SetStdZoomRect( const Rect& aRect )
  1365. {
  1366.     short    v = GetWVariant( macWindow );
  1367.  
  1368.     if (v == zoomDocProc ||
  1369.         v == zoomNoGrow)
  1370.         SetWindowStandardState( macWindow, &aRect );    // using copland macro
  1371. }
  1372.  
  1373. /*------------------------------***  SETUSERZOOMRECT  ***-------------------------------*/
  1374. /*    
  1375. set the user rect for zoomable windows. The window zooms to this rect when the zoom box
  1376. is clicked and zoomed out. The rect is in global coords.
  1377. ----------------------------------------------------------------------------------------*/
  1378.  
  1379. void    ZWindow::SetUserZoomRect( const Rect& aRect )
  1380. {
  1381.     short    v = GetWVariant( macWindow );
  1382.  
  1383.     if (v == zoomDocProc ||
  1384.         v == zoomNoGrow)
  1385.         SetWindowUserState( macWindow, &aRect );        // using copland macro
  1386. }
  1387.  
  1388.  
  1389. #pragma mark -
  1390.  
  1391. /*-----------------------------------***  SAVE  ***-------------------------------------*/
  1392. /*    
  1393.  
  1394. save the contents of the window to a file. This may display the standard file dialog.
  1395. ----------------------------------------------------------------------------------------*/
  1396.  
  1397. Boolean    ZWindow::Save( const Boolean forceSaveAs )
  1398. {
  1399.     // handles the save and save as commands.
  1400.     
  1401.     Boolean        requiresNavPostProcess = FALSE;
  1402.     
  1403. #if _USE_NAVIGATION_SERVICES
  1404.     NavReplyRecord        navReply;
  1405.     OSErr                theErr;
  1406. #endif
  1407.     
  1408.     if (! isNamed || forceSaveAs)
  1409.     {
  1410.         // do Save As
  1411.         
  1412.     #if _USE_NAVIGATION_SERVICES
  1413.         
  1414.         if ( gMacInfo.hasNavigationServices )
  1415.         {
  1416.             PickFile( &navReply );
  1417.             
  1418.             if ( navReply.validRecord )
  1419.             {
  1420.                 AEDesc    specDesc;
  1421.                 FInfo    fi;
  1422.         
  1423.                 FailOSErr( AEGetNthDesc( &navReply.selection, 1, typeFSS, NULL, &specDesc ));
  1424.         
  1425.                 BlockMoveData( *specDesc.dataHandle, &macFile, sizeof( FSSpec ));
  1426.             
  1427.                 // to get the type we need to do a FSpGetFInfo, which may return fnfErr
  1428.             
  1429.                 theErr = FSpGetFInfo( &macFile, &fi );
  1430.             
  1431.                 if ( theErr == noErr )
  1432.                     macFType = fi.fdType;
  1433.                     
  1434.                 requiresNavPostProcess = TRUE;
  1435.             }
  1436.             else
  1437.             {
  1438.                 NavDisposeReply( &navReply );
  1439.                 return FALSE;
  1440.             }
  1441.         }
  1442.         else
  1443.         {
  1444.     #endif
  1445.             StandardFileReply    macReply;
  1446.             
  1447.             PickFile( &macReply );
  1448.             
  1449.             if ( macReply.sfGood )
  1450.                 macFile = macReply.sfFile;
  1451.             else
  1452.                 return FALSE;        // user cancelled the save
  1453.         #if _USE_NAVIGATION_SERVICES
  1454.         }
  1455.         #endif
  1456.     }
  1457.     
  1458.     // now do a save with the info.
  1459.     
  1460.     SetWatchCursor();
  1461.     SaveFile();
  1462.     
  1463.     #if _USE_NAVIGATION_SERVICES
  1464.     
  1465.     if ( gMacInfo.hasNavigationServices && requiresNavPostProcess )
  1466.     {
  1467.         NavCompleteSave( &navReply, kNavTranslateInPlace );
  1468.         NavDisposeReply( &navReply );
  1469.     }
  1470.     #endif
  1471.     
  1472.     return TRUE;
  1473. }
  1474.  
  1475.  
  1476. /*---------------------------------***  PICKFILE  ***-----------------------------------*/
  1477. /*    
  1478.  
  1479. display standard file dialog for picking a file for saving. Override if you want custom
  1480. dialog, etc.
  1481.  
  1482. ----------------------------------------------------------------------------------------*/
  1483.  
  1484. void    ZWindow::PickFile( StandardFileReply* macReply )
  1485. {
  1486.     Str31    prompt;
  1487.     Str255     name;
  1488.     
  1489.     GetIndString( prompt, kMiscStrListID, 3 );
  1490.     GetName( name );
  1491.     
  1492.     // make sure that filename is no longer than 31 chars
  1493.     
  1494.     name[0] = MIN( name[0], 31 );
  1495.     
  1496.     // here, we use the "classic" standard file dialog:
  1497.     
  1498.     gWindowManager->DeactivateForDialog( sfPutDialogID );
  1499.     StandardPutFile( prompt, name, macReply );
  1500.     gWindowManager->Activate();
  1501. }
  1502.  
  1503.  
  1504. #if _USE_NAVIGATION_SERVICES
  1505.  
  1506. void    ZWindow::PickFile( NavReplyRecord* navReply )
  1507. {
  1508.     OSErr                theErr;
  1509.     NavDialogOptions    navOptions;
  1510.     
  1511.     FailOSErr( NavGetDefaultDialogOptions( &navOptions ));
  1512.     gApplication->GetName( navOptions.clientName );
  1513.     GetName( navOptions.savedFileName );
  1514.     gWindowManager->DeactivateForDialog( -1, FALSE );
  1515.     
  1516.     theErr = NavPutFile( NULL,
  1517.                          navReply,
  1518.                          &navOptions,
  1519.                          gNavEventHandler,
  1520.                          macFType,
  1521.                          gAppSignature,
  1522.                          (NavCallBackUserData) this );
  1523.                          
  1524.     gWindowManager->Activate();
  1525. }
  1526.  
  1527. #endif
  1528.  
  1529.  
  1530.  
  1531. /*---------------------------------***  SAVEFILE  ***-----------------------------------*/
  1532. /*    
  1533.  
  1534. write out the contents of the window to a file. This may rename the window. Note that you
  1535. need to override this to actually write to a file (using a ZFile, perhaps), then call the
  1536. inherited method to set the name and the state flags.
  1537.  
  1538. ----------------------------------------------------------------------------------------*/
  1539.  
  1540.  
  1541. void    ZWindow::SaveFile()
  1542. {
  1543.     // actually save the window's contents to the file.
  1544.     
  1545.     if ( macFile.vRefNum != kNoFile )
  1546.     {
  1547.         SetTitle( macFile.name );
  1548.         
  1549.         // no longer dirty
  1550.         
  1551.         isNamed = TRUE;
  1552.         dirty = FALSE;
  1553.         
  1554.         // save the window's position to the file
  1555.         
  1556.         SavePosition();
  1557.     }
  1558. }
  1559.  
  1560.  
  1561. /*---------------------------------***  GETNAME  ***------------------------------------*/
  1562. /*    
  1563.  
  1564. return the name of the window
  1565.  
  1566. ----------------------------------------------------------------------------------------*/
  1567.  
  1568. void    ZWindow::GetName( Str255 name )
  1569. {
  1570.     GetWTitle( macWindow, name );
  1571. }
  1572.  
  1573.  
  1574.  
  1575. /*----------------------------------***  REVERT  ***------------------------------------*/
  1576. /*    
  1577.  
  1578. revert the contents of the window to the original file
  1579.  
  1580. ----------------------------------------------------------------------------------------*/
  1581.  
  1582. void    ZWindow::Revert()
  1583. {
  1584.     // revert the contents. By default, this just calls open.
  1585.     
  1586.     #if _USE_NAV_SAVEREVERT_ALERTS
  1587.     if ( gMacInfo.hasNavigationServices )
  1588.     {
  1589.         NavDialogOptions            navOptions;
  1590.         NavAskDiscardChangesResult    navResult;
  1591.         
  1592.         GetName( navOptions.savedFileName );
  1593.         
  1594.         FailOSErr( NavAskDiscardChanges( &navOptions,
  1595.                                          &navResult,
  1596.                                          gNavEventHandler,
  1597.                                          (NavCallBackUserData) this ));
  1598.                                          
  1599.         if ( navResult == kNavAskDiscardChanges )
  1600.         {
  1601.             SetWatchCursor();
  1602.             OpenFile( macFType );
  1603.         }
  1604.     }
  1605.     else
  1606.     {
  1607.     #endif
  1608.     Str31    title;
  1609.     
  1610.     GetName( title );
  1611.     ParamText( title, NULL, NULL, NULL );
  1612.     
  1613.     if ( NotifyAlert( kRevertConfirmAlertID ) == ok )
  1614.     {
  1615.         SetWatchCursor();
  1616.         OpenFile( macFType );
  1617.     }
  1618.     #if _USE_NAV_SAVEREVERT_ALERTS
  1619.     }
  1620.     #endif
  1621. }
  1622.  
  1623.  
  1624. /*---------------------------------***  SETFILE  ***------------------------------------*/
  1625. /*    
  1626.  
  1627. set the filespec for this window to the file passed.
  1628.  
  1629. ----------------------------------------------------------------------------------------*/
  1630.  
  1631. void    ZWindow::SetFile( const FSSpec& aFile )
  1632. {
  1633.     macFile = aFile;
  1634. }
  1635.  
  1636.  
  1637. /*---------------------------------***  OPENFILE  ***-----------------------------------*/
  1638. /*    
  1639.  
  1640. open the file into the window's contents. This will set the name of the window to equal
  1641. the filename
  1642.  
  1643. ----------------------------------------------------------------------------------------*/
  1644.  
  1645. void    ZWindow::OpenFile( const OSType aFileType, Boolean isStationery )
  1646. {
  1647.     // this opens the current file into this window. This function should read the
  1648.     // contents of the file, replacing the current contents.
  1649.     // You should check that the vRefNum of the file spec is not kNoFile.
  1650.     // Call the inherited method to maintain the proper window state variables.
  1651.     
  1652.     if ( macFile.vRefNum != kNoFile )
  1653.     {
  1654.         macFType = aFileType;
  1655.         
  1656.         if ( ! isStationery )
  1657.         {
  1658.             SetTitle(macFile.name);
  1659.             isNamed = TRUE;
  1660.         }
  1661.         
  1662.         stationeryFile = isStationery;
  1663.         
  1664.         if ( IsVisible())
  1665.             PostRefresh();
  1666.             
  1667.         // delete any existing undo task for this window after opening a file,
  1668.         // since it probably contains stale data.
  1669.         
  1670.         ZUndoTask*    task = gApplication->GetUndoTask();
  1671.         
  1672.         if ( task && ( task->GetUndoTarget() == this ))
  1673.             gApplication->SetTask( NULL );
  1674.         
  1675.         dirty = FALSE;
  1676.     }
  1677. }
  1678.  
  1679.  
  1680. /*---------------------------------***  SETTITLE  ***-----------------------------------*/
  1681. /*    
  1682.  
  1683. set the title of the window
  1684. ----------------------------------------------------------------------------------------*/
  1685.  
  1686. void    ZWindow::SetTitle( Str255 aTitle )
  1687. {
  1688.     SetWTitle( macWindow, aTitle );
  1689. }
  1690.  
  1691.  
  1692.  
  1693. /*---------------------------------***  ISVISIBLE  ***----------------------------------*/
  1694. /*    
  1695.  Is the window visible on screen?
  1696. ----------------------------------------------------------------------------------------*/
  1697.  
  1698. Boolean    ZWindow::IsVisible()
  1699. {
  1700.     if ( macWindow )
  1701.         return ((WindowPeek) macWindow)->visible;
  1702.     else
  1703.         return FALSE;
  1704. }
  1705.  
  1706.  
  1707. /*----------------------------------***  ISACTIVE  ***----------------------------------*/
  1708. /*    
  1709.  Is the window currently activated?
  1710. ----------------------------------------------------------------------------------------*/
  1711.  
  1712. Boolean    ZWindow::IsActive()
  1713. {
  1714.     if ( macWindow )
  1715.         return ((WindowPeek) macWindow)->hilited;
  1716.     else
  1717.         return FALSE;
  1718. }
  1719.  
  1720.  
  1721. /*-----------------------------***  GETTITLEBARHEIGHT  ***------------------------------*/
  1722. /*    
  1723.  return the actual height of the window's title bar. This measures it from the regions
  1724.  and is thus totally WDEF safe.
  1725. ----------------------------------------------------------------------------------------*/
  1726.  
  1727. short    ZWindow::GetTitleBarHeight()
  1728. {
  1729.     RgnHandle    sRgn, cRgn;
  1730.     short        tHeight;
  1731.     
  1732.     FailNIL( sRgn = NewRgn());
  1733.     FailNIL( cRgn = NewRgn());
  1734.     
  1735.     GetStructureRegion( sRgn );
  1736.     GetContentRegion( cRgn );
  1737.     
  1738.     tHeight =  (*cRgn)->rgnBBox.top - (*sRgn)->rgnBBox.top;
  1739.     
  1740.     DisposeRgn( sRgn );
  1741.     DisposeRgn( cRgn );
  1742.     
  1743.     return tHeight;
  1744. }
  1745.  
  1746.  
  1747. /*----------------------------***  GETSTRUCTUREREGION  ***------------------------------*/
  1748. /*    
  1749.  copies the window's structure region into the passed region
  1750. ----------------------------------------------------------------------------------------*/
  1751.  
  1752. void    ZWindow::GetStructureRegion( RgnHandle aRgn )
  1753. {
  1754.     FailNILParam( aRgn );
  1755.     
  1756.     WindowPeek    w = ( WindowPeek ) macWindow;
  1757.     
  1758.     Boolean wasFudged = FALSE;
  1759.     short    h, v;
  1760.     Rect    saveUserRect;
  1761.     
  1762.     // if the window isn't visible, the structure region isn't valid, so we have to
  1763.     // make it visible offscreen in order to get the region
  1764.     
  1765.     if ( ! w->visible )
  1766.     {
  1767.         GetWindowUserState( macWindow, &saveUserRect );    
  1768.         GetGlobalPosition( &h, &v ); 
  1769.         
  1770.         MoveWindow( macWindow, h + 10000, v + 100, FALSE );
  1771.         ShowHide( macWindow, TRUE );
  1772.         
  1773.         wasFudged = TRUE;
  1774.     }
  1775.     
  1776.     CopyRgn( w->strucRgn, aRgn );
  1777.     
  1778.     if ( wasFudged )
  1779.     {
  1780.         ShowHide( macWindow, FALSE );    
  1781.         MoveWindow( macWindow, h, v, FALSE );
  1782.         
  1783.         OffsetRgn( aRgn, -10000, -100 );
  1784.         
  1785.         SetWindowUserState( macWindow, &saveUserRect );
  1786.     }
  1787. }
  1788.  
  1789.  
  1790. /*-----------------------------***  GETCONTENTREGION  ***-------------------------------*/
  1791. /*    
  1792.  copies the window's content region into the passed region
  1793. ----------------------------------------------------------------------------------------*/
  1794.  
  1795. void    ZWindow::GetContentRegion( RgnHandle aRgn )
  1796. {
  1797.     FailNILParam( aRgn );
  1798.     
  1799.     WindowPeek    w = ( WindowPeek ) macWindow;
  1800.     
  1801.     Boolean wasFudged = FALSE;
  1802.     short    h, v;
  1803.     Rect    saveUserRect;
  1804.     
  1805.     // if the window isn't visible, the content region isn't valid, so we have to
  1806.     // make it visible offscreen in order to get the region
  1807.     
  1808.     if ( ! w->visible )
  1809.     {
  1810.         GetWindowUserState( macWindow, &saveUserRect );    
  1811.         GetGlobalPosition( &h, &v ); 
  1812.         
  1813.         MoveWindow( macWindow, h + 10000, v + 100, FALSE );
  1814.         ShowHide( macWindow, TRUE );
  1815.         
  1816.         wasFudged = TRUE;
  1817.     }
  1818.     
  1819.     CopyRgn( w->contRgn, aRgn );
  1820.     
  1821.     if ( wasFudged )
  1822.     {
  1823.         ShowHide( macWindow, FALSE );    
  1824.         MoveWindow( macWindow, h, v, FALSE );
  1825.         
  1826.         OffsetRgn( aRgn, -10000, -100 );
  1827.         SetWindowUserState( macWindow, &saveUserRect );
  1828.     }
  1829. }
  1830.  
  1831.  
  1832. /*-------------------------***  GETSTRUCTUREFRAMEBORDER  ***----------------------------*/
  1833. /*    
  1834.  returns in <aRect> the thicknesses of the window borders. <top> is the title bar height,
  1835.  <left> and <right> are the thicknesses of the edges, and <bottom> is the thickness of the
  1836.  bottom.
  1837. ----------------------------------------------------------------------------------------*/
  1838.  
  1839. void    ZWindow::GetStructureFrameBorder( Rect* aRect )
  1840. {
  1841.     RgnHandle    sRgn, cRgn;
  1842.     Rect        s, c;
  1843.     
  1844.     FailNILParam( aRect );
  1845.     
  1846.     FailNIL( sRgn = NewRgn());
  1847.     FailNIL( cRgn = NewRgn());
  1848.     
  1849.     GetStructureRegion( sRgn );
  1850.     GetContentRegion( cRgn );
  1851.     
  1852.     s = (*sRgn)->rgnBBox;
  1853.     c = (*cRgn)->rgnBBox;
  1854.     
  1855.     aRect->top         = c.top    - s.top;
  1856.     aRect->left     = c.left   - s.left;
  1857.     aRect->right     = s.right  - c.right;
  1858.     aRect->bottom     = s.bottom - c.bottom;
  1859.     
  1860.     DisposeRgn( sRgn );
  1861.     DisposeRgn( cRgn );
  1862. }
  1863.  
  1864.  
  1865. /*-----------------------------***  GETGLOBALPOSITION  ***------------------------------*/
  1866. /*    
  1867.  returns the global position of the window on screen
  1868. ----------------------------------------------------------------------------------------*/
  1869.  
  1870. void    ZWindow::GetGlobalPosition( short* hGlobal, short* vGlobal )
  1871. {
  1872.     GrafPtr        savePort;
  1873.     Point        gloc;
  1874.     
  1875.     GetPort( &savePort );
  1876.     SetPort( macWindow );
  1877.     
  1878.     gloc = topLeft( macWindow->portRect );
  1879.     LocalToGlobal( &gloc );
  1880.     
  1881.     SetPort( savePort );
  1882.     
  1883.     *hGlobal = gloc.h;
  1884.     *vGlobal = gloc.v;
  1885. }
  1886.  
  1887.  
  1888. /*-------------------------------***  WRITETOSTREAM  ***--------------------------------*/
  1889. /*    
  1890. write the window state to the stream. You can save an entire window to the stream and
  1891. recreate it exactly later on without needing any resources, etc.
  1892. ----------------------------------------------------------------------------------------*/
  1893.  
  1894. void    ZWindow::WriteToStream( ZStream* aStream )
  1895. {
  1896. #if _MACZOOP_STREAMS
  1897.     ZCommander::WriteToStream( aStream );
  1898.     
  1899.     // save window state info to the stream. This includes its position, title, visible
  1900.     // and floating flags, ID, etc, etc.
  1901.     
  1902.     short    h, v;
  1903.     Str255    title;
  1904.     
  1905.     // write essential data stored in <macWindow> first...
  1906.     
  1907.     aStream->WriteRect( &macWindow->portRect );
  1908.     
  1909.     aStream->WriteChar( IsVisible());
  1910.     aStream->WriteShort( GetWVariant( macWindow ));
  1911.     GetName( title );
  1912.     aStream->WriteString( title );
  1913.     aStream->WriteChar(((WindowPeek) macWindow )->goAwayFlag );
  1914.     
  1915.     // write grafport state
  1916.     
  1917.     aStream->WriteGrafPort( macWindow );
  1918.     
  1919.     // write global window position...
  1920.     
  1921.     GetGlobalPosition( &h, &v );
  1922.     aStream->WriteShort( h );
  1923.     aStream->WriteShort( v );
  1924.     
  1925.     // write various data members...
  1926.     
  1927.     aStream->WriteRect( &sizeRect );
  1928.     aStream->WriteShort( windID );
  1929.     aStream->WriteChar( isNamed );
  1930.     aStream->WriteChar( stationeryFile );
  1931.     aStream->WriteData((Ptr) &macFile, sizeof( FSSpec ));
  1932.     aStream->WriteLong((long) macFType );
  1933.     aStream->WriteChar( printable );
  1934.     aStream->WriteChar( floating );
  1935.     aStream->WriteChar( disableAutoClose );
  1936.     aStream->WriteRect( &zoomSource );
  1937. #endif
  1938. }
  1939.  
  1940.  
  1941. /*------------------------------***  READFROMSTREAM  ***--------------------------------*/
  1942. /*    
  1943. recover the window state from the stream. Normally this is called to actually create a
  1944. window from the stream (i.e. InitZWindow is not called). Thus this uses the stream data
  1945. to make the window and should not be used to change an existing one.
  1946. ----------------------------------------------------------------------------------------*/
  1947.  
  1948. void    ZWindow::ReadFromStream( ZStream* aStream )
  1949. {
  1950. #if _MACZOOP_STREAMS
  1951.     ZCommander::ReadFromStream( aStream );
  1952.     
  1953.     Rect        pr;
  1954.     Boolean        vis, goAway;
  1955.     short        varCode, h, v;
  1956.     long        dLen; 
  1957.     Str255        title;
  1958.     
  1959.     aStream->ReadRect( &pr );
  1960.     aStream->ReadChar((char*) &vis );
  1961.     aStream->ReadShort( &varCode );
  1962.     aStream->ReadString( title );
  1963.     aStream->ReadChar((char*) &goAway );
  1964.     
  1965.     MakeMacWindow( &pr, title, vis, varCode, goAway );
  1966.     
  1967.     // read grafport state
  1968.     
  1969.     aStream->ReadGrafPort( macWindow );
  1970.  
  1971.     // read the rest of our data...
  1972.     
  1973.     aStream->ReadShort( &h );
  1974.     aStream->ReadShort( &v );
  1975.     MoveWindow( macWindow, h, v, FALSE );
  1976.     
  1977.     aStream->ReadRect( &sizeRect );
  1978.     aStream->ReadShort( &windID );
  1979.     aStream->ReadChar((char*) &isNamed );
  1980.     aStream->ReadChar((char*) &stationeryFile );
  1981.     dLen = sizeof( FSSpec );
  1982.     aStream->ReadData((Ptr) &macFile, &dLen );
  1983.     aStream->ReadLong((long*) &macFType );
  1984.     aStream->ReadChar((char*) &printable );
  1985.     aStream->ReadChar((char*) &floating );
  1986.     aStream->ReadChar((char*) &disableAutoClose );
  1987.     aStream->ReadRect( &zoomSource );
  1988.     
  1989.     // register with window manager...
  1990.     
  1991.     gWindowManager->AddWindow( this );
  1992. #endif
  1993. }
  1994.  
  1995. #pragma mark -
  1996.  
  1997. /*------------------------------------***  DRAG  ***------------------------------------*/
  1998. /*    
  1999.  
  2000. initiate a drag from this window
  2001. ----------------------------------------------------------------------------------------*/
  2002.  
  2003. Boolean    ZWindow::Drag( const Point startPt )
  2004. {
  2005.     // this can be called to instigate a drag from this window. When your mouse dragging method
  2006.     // wants to perform a drag, it calls this. This then builds the drag region and drag data
  2007.     // by calling some additional methods. You can override those methods to implement the drag
  2008.     // data, etc you require. <startPt> is in local coordinates, as passed from Click, e.g.
  2009.     
  2010.     DragReference     theDrag;
  2011.     RgnHandle        dragRgn = NULL;
  2012.     unsigned short    diCount;
  2013.     EventRecord        theEvent;
  2014.     Boolean            result = TRUE;
  2015.     
  2016.     if ( MacHasDM())
  2017.     {
  2018.         // make absolutely sure we are the current port, etc.
  2019.         
  2020.         Focus();
  2021.         FailOSErr( NewDrag( &theDrag ));
  2022.         
  2023.         // add data to the drag
  2024.         
  2025.         try
  2026.         {
  2027.             MakeDragData( theDrag );    
  2028.     
  2029.             // if no data was added to the drag (the default case, in fact) do not
  2030.             // bother to do anything else
  2031.             
  2032.             FailOSErr( CountDragItems( theDrag, &diCount ));
  2033.             
  2034.             if ( diCount > 0 )
  2035.             {
  2036.                 // make a drag region
  2037.                 
  2038.                 FailNIL( dragRgn = MakeDragRgn());
  2039.                 
  2040.                 // make a dummy event record
  2041.                 
  2042.                 theEvent.what = mouseDown;
  2043.                 theEvent.where = startPt;
  2044.                 LocalToGlobal(&theEvent.where);
  2045.                 theEvent.when = TickCount();
  2046.                 theEvent.message = 0;
  2047.                 theEvent.modifiers = 0;
  2048.                 
  2049.                 // do that drag manager thang!
  2050.                 
  2051.                 FailOSErr( TrackDrag( theDrag, &theEvent, dragRgn ));
  2052.             }
  2053.         }
  2054.         catch ( OSErr err )
  2055.         {
  2056.             // do not propagate exceptions
  2057.             
  2058.             result = FALSE;
  2059.         }
  2060.         
  2061.         DisposeDrag( theDrag );
  2062.         
  2063.         if ( dragRgn )
  2064.             DisposeRgn( dragRgn );
  2065.     }
  2066.     
  2067.     return result;
  2068. }
  2069.  
  2070.  
  2071. /*--------------------------------***  MAKEDRAGRGN  ***---------------------------------*/
  2072. /*    
  2073.  
  2074. create the drag outline. This uses the content rect by default
  2075. ----------------------------------------------------------------------------------------*/
  2076.  
  2077. RgnHandle    ZWindow::MakeDragRgn()
  2078. {
  2079.     // override to build the drag region you require. By default, the drag region is the content
  2080.     // region of the window.
  2081.     
  2082.     Rect        content;
  2083.     RgnHandle    dragRgn, temp;
  2084.     Point        origin = {0,0};
  2085.  
  2086.     FailNIL( dragRgn = NewRgn());
  2087.     FailNIL( temp = NewRgn());
  2088.     
  2089.     GetContentRect( &content );
  2090.     RectRgn( dragRgn, &content );
  2091.     CopyRgn( dragRgn, temp );
  2092.     InsetRgn( temp, 1, 1 );
  2093.     DiffRgn( dragRgn, temp, dragRgn );
  2094.     
  2095.     DisposeRgn( temp );
  2096.     
  2097.     // convert into global corrdinates
  2098.     
  2099.     LocalToGlobal( &origin );
  2100.     OffsetRgn( dragRgn, origin.h, origin.v );
  2101.     
  2102.     return dragRgn;
  2103. }
  2104.  
  2105.  
  2106. /*---------------------------------***  DRAGHILITE  ***---------------------------------*/
  2107. /*    
  2108.  
  2109. hilite the window in response to a drag over it
  2110. ----------------------------------------------------------------------------------------*/
  2111.  
  2112. void    ZWindow::DragHilite( const Boolean state, const DragReference theDrag)
  2113. {
  2114.     // hilites the window. This uses the drag manager's default hiliting.
  2115.     
  2116.     RgnHandle    dragHiliteRgn;
  2117.     Rect        content;
  2118.     
  2119.     Focus();
  2120.     
  2121.     if ( state )
  2122.     {
  2123.         // make the hilite region
  2124.         
  2125.         FailNIL( dragHiliteRgn = NewRgn());    
  2126.     
  2127.         GetContentRect( &content );
  2128.         RectRgn( dragHiliteRgn, &content );
  2129.         
  2130.         (void) ShowDragHilite( theDrag, dragHiliteRgn, TRUE );
  2131.         
  2132.         DisposeRgn( dragHiliteRgn );
  2133.     }
  2134.     else
  2135.         (void) HideDragHilite( theDrag );
  2136.  
  2137. }
  2138.  
  2139. /*----------------------------***  INSTALLDRAGHANDLERS  ***-----------------------------*/
  2140. /*    
  2141.  
  2142. install the procs that call this during a drag
  2143.  
  2144. ----------------------------------------------------------------------------------------*/
  2145.  
  2146. void    ZWindow::InstallDragHandlers()
  2147. {
  2148.     // set up the drag handler proc to call this object when a drag occurs over this window. The
  2149.     // window's refCon field contains the object reference, so the handler can find this object.
  2150.     
  2151.     FailOSErr( InstallTrackingHandler( gDragTrackProc,      macWindow, 0L ));
  2152.     FailOSErr( InstallReceiveHandler ( gDragReceiveProc, macWindow, 0L ));    
  2153. }
  2154.  
  2155.  
  2156. /*----------------------------***  REMOVEDRAGHANDLERS  ***------------------------------*/
  2157. /*    
  2158.  
  2159. get rid of the handlers. This is called by the destructor
  2160.  
  2161. ----------------------------------------------------------------------------------------*/
  2162.  
  2163. void    ZWindow::RemoveDragHandlers()
  2164. {
  2165.     // removes the drag handlers when the window is deleted
  2166.     
  2167.     OSErr    theErr;
  2168.     
  2169.     theErr = RemoveTrackingHandler( gDragTrackProc,   macWindow );    
  2170.     theErr = RemoveReceiveHandler ( gDragReceiveProc, macWindow );    
  2171. }
  2172.  
  2173.  
  2174.  
  2175. /*--------------------------------***  DROPHANDLER  ***---------------------------------*/
  2176. /*    
  2177.  
  2178. unpacks the data from an accepted drag and passes it to the Drop method.
  2179.  
  2180. ----------------------------------------------------------------------------------------*/
  2181.  
  2182. void    ZWindow::DropHandler( const DragReference theDrag )
  2183. {
  2184.     // method to dispatch drops from the drag manager. This unpacks the drag data, and for
  2185.     // each flavour that the AcceptsFlavour method returns TRUE for, will call Drop with the
  2186.     // data of the item.
  2187.     
  2188.     unsigned short    dragItemCount, i;
  2189.     unsigned short    dragFlavourCount, f;
  2190.     ItemReference    iRef;
  2191.     FlavorType        theFlavour;
  2192.     Boolean            atLeastOneAccepted = FALSE;
  2193.     Size            dataSize;
  2194.     Ptr                theData = NULL;
  2195.     
  2196.     DragHilite( FALSE, theDrag );
  2197.     FailOSErr( CountDragItems( theDrag, &dragItemCount ));
  2198.     
  2199.     SetBeachBallCursor();
  2200.     
  2201.     for ( i = 1; i <= dragItemCount; i++ )
  2202.     {
  2203.         // get the item
  2204.         
  2205.         FailOSErr( GetDragItemReferenceNumber( theDrag, i, &iRef ));    
  2206.     
  2207.         // count the flavours in the item
  2208.         
  2209.         FailOSErr( CountDragItemFlavors( theDrag, iRef, &dragFlavourCount ));
  2210.         
  2211.         // for each flavour, if we can accept the flavour, unpack it and pass the data
  2212.         // to the drop method.
  2213.         
  2214.         for ( f = 1; f <= dragFlavourCount; f++ )
  2215.         {
  2216.             FailOSErr( GetFlavorType( theDrag, iRef, f, &theFlavour ));
  2217.         
  2218.             if ( AcceptsFlavour( theFlavour ))
  2219.             {
  2220.                 // get the data for this object
  2221.                 
  2222.                 FailOSErr( GetFlavorDataSize( theDrag, iRef, theFlavour, &dataSize ));
  2223.                 
  2224.                 // create a buffer big enough to hold the object
  2225.                 
  2226.                 FailNIL( theData = NewPtr( dataSize ));
  2227.                 
  2228.                 // get the data into the buffer
  2229.                 
  2230.                 try
  2231.                 {
  2232.                     FailOSErr( GetFlavorData( theDrag, iRef, theFlavour, theData, &dataSize, 0L ));
  2233.                 
  2234.                     // call the method to handle the drop
  2235.                     
  2236.                     Drop( theFlavour, theData, dataSize, theDrag );    
  2237.                 }
  2238.                 catch( OSErr err )
  2239.                 {
  2240.                     if ( theData )
  2241.                         DisposePtr( theData );
  2242.                         
  2243.                     theData = NULL;
  2244.                     
  2245.                     throw err;    
  2246.                 }    
  2247.                 if ( theData )
  2248.                     DisposePtr( theData );
  2249.                     
  2250.                 theData = NULL;
  2251.                 atLeastOneAccepted = TRUE;
  2252.             }
  2253.         }
  2254.     }
  2255.     
  2256.     // if nothing in this drag was accepted (unlikely???), throw an error
  2257.     // so that the drag manager gives the right feedback
  2258.     
  2259.     if (! atLeastOneAccepted)
  2260.         FailOSErr( dragNotAcceptedErr );
  2261. }
  2262.  
  2263.  
  2264.  
  2265. /*-------------------------------***  TRACKTHEDRAG  ***---------------------------------*/
  2266. /*    
  2267.  
  2268. dispatches tracking messages to the appropriate method
  2269. ----------------------------------------------------------------------------------------*/
  2270.  
  2271.  
  2272. void    ZWindow::DragDispatch( const DragTrackingMessage theMessage, const DragReference theDrag )
  2273. {
  2274.     // this method handles the tracking of a drag within this window. It calls various other
  2275.     // methods to implement its behaviour- normally you would override those where necessary
  2276.     // rather than this, which is quite low-level.
  2277.     
  2278.     switch ( theMessage )
  2279.     {    
  2280.         case kDragTrackingEnterHandler:
  2281.             EnteredHandler( theDrag );
  2282.             break;
  2283.         
  2284.         case kDragTrackingEnterWindow:
  2285.             EnteredWindow( theDrag );
  2286.             break;
  2287.         
  2288.         case kDragTrackingInWindow:
  2289.             InWindow( theDrag );
  2290.             break;
  2291.         
  2292.         case kDragTrackingLeaveWindow:
  2293.             LeftWindow( theDrag );
  2294.             break;
  2295.         
  2296.         case kDragTrackingLeaveHandler:
  2297.             LeftHandler( theDrag );
  2298.             break;
  2299.     }
  2300. }
  2301.  
  2302.  
  2303. /*-------------------------------***  ENTEREDWINDOW  ***--------------------------------*/
  2304. /*    
  2305.  
  2306. the window was made the target of the drag. This hilites it if any flavour in the drag is
  2307. acceptable.
  2308. ----------------------------------------------------------------------------------------*/
  2309.  
  2310. void    ZWindow::EnteredWindow( const DragReference theDrag)
  2311. {
  2312.     // the drag has enetered this window. If the window accepts any of the flavours in the drag,
  2313.     // hilite the window.
  2314.  
  2315.     unsigned short    dragItemCount;
  2316.     unsigned short    dragFlavourCount;
  2317.     ItemReference    iRef;
  2318.     FlavorType        theFlavour;
  2319.     
  2320.     
  2321.     
  2322.     FailOSErr(CountDragItems(theDrag, &dragItemCount));
  2323.     
  2324.     if (dragItemCount)
  2325.     {
  2326.         do
  2327.         {
  2328.             // for each drag item, count the flavours
  2329.             
  2330.             FailOSErr(GetDragItemReferenceNumber(theDrag, dragItemCount, &iRef));
  2331.             FailOSErr(CountDragItemFlavors(theDrag, iRef, &dragFlavourCount));
  2332.             
  2333.             // for each flavour, see if we can accept it. As soon as we get one that we can
  2334.             // handle, we hilite the window and exit.
  2335.             
  2336.             do
  2337.             {
  2338.                 FailOSErr(GetFlavorType(theDrag, iRef, dragFlavourCount, &theFlavour));    
  2339.             
  2340.                 if (AcceptsFlavour(theFlavour))
  2341.                 {
  2342.                     DragHilite(TRUE, theDrag);
  2343.                     return;
  2344.                 }
  2345.             }
  2346.             while(--dragFlavourCount);
  2347.         }
  2348.         while(--dragItemCount);
  2349.     }
  2350. }
  2351.  
  2352. /*---------------------------------***  LEFTWINDOW  ***---------------------------------*/
  2353. /*    
  2354.  
  2355. the drag is no longer in this window. This unhilites the drag here.
  2356. ----------------------------------------------------------------------------------------*/
  2357.  
  2358. void    ZWindow::LeftWindow( const DragReference theDrag)
  2359. {
  2360.     // Ladies and Gentlemen, the drag has left the window. Please leave in an orderly fashion.
  2361.     
  2362.     DragHilite( FALSE, theDrag );
  2363. }
  2364.  
  2365.  
  2366. /*-------------------------------***  SHOWBALLOONHELP  ***------------------------------*/
  2367. /*    
  2368.  
  2369. display a help ballon for the passed local rectangle
  2370. ----------------------------------------------------------------------------------------*/
  2371.  
  2372. void    ZWindow::ShowBalloonHelp( Rect* localRect, Point tip, HMMessageRecord* hm )
  2373. {
  2374.     OSErr    hmErr;
  2375.     Rect    gr = *localRect;
  2376.     
  2377.     Focus();
  2378.     
  2379.     LocalToGlobal( &topLeft( gr ));
  2380.     LocalToGlobal( &botRight( gr ));
  2381.     LocalToGlobal( &tip );
  2382.     
  2383.     hmErr = HMShowBalloon( hm, tip, &gr, NULL, 0, 0, kHMRegularWindow );
  2384. }
  2385.  
  2386.  
  2387. #pragma mark -
  2388. /*---------------------------------******************----------------------------------*/
  2389.  
  2390. static short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint, short idealOnScreenStartPoint,
  2391.                             short idealOnScreenEndPoint, short screenEdge1, short screenEdge2)
  2392. {
  2393.     short    offsetAmount;
  2394.  
  2395.     // First check to see if the window fits on the screen in this dimension.
  2396.     if ((idealStartPoint < screenEdge1) && (idealEndPoint > screenEdge2))
  2397.         offsetAmount = 0;
  2398.     else
  2399.     {
  2400.     
  2401.         // Find out how much of the window lies off this screen by subtracting the amount of the window
  2402.         // that is on the screen from the size of the entire window in this dimension. If the window
  2403.         // is completely offscreen, the offset amount is going to be the distance from the ideal
  2404.         // starting point to the first edge of the screen.
  2405.         if ((idealOnScreenStartPoint - idealOnScreenEndPoint) == 0)
  2406.         {
  2407.             // See if the window is lying to the left or above the screen
  2408.             if (idealEndPoint < screenEdge1)
  2409.                 offsetAmount = screenEdge1 - idealStartPoint + kNudgeSlop;
  2410.             else
  2411.             // Otherwise, it’s below or to the right of the screen
  2412.                 offsetAmount = screenEdge2 - idealEndPoint - kNudgeSlop;
  2413.         }
  2414.         else
  2415.         {
  2416.             // Window is already partially or completely on the screen
  2417.             offsetAmount = (idealEndPoint - idealStartPoint) -
  2418.                             (idealOnScreenEndPoint - idealOnScreenStartPoint);
  2419.     
  2420.             // If we are offscreen a little, move the window in a few more pixels from the edge of the screen.
  2421.             if (offsetAmount != 0)
  2422.                 offsetAmount += kNudgeSlop;
  2423.             
  2424.             // Check to see which side of the screen the window was falling off of, so that it can be
  2425.             // nudged in the opposite direction.
  2426.             if (idealEndPoint > screenEdge2)
  2427.                 offsetAmount = -offsetAmount;
  2428.         }
  2429.     }
  2430.     
  2431.     return offsetAmount;
  2432. }
  2433.  
  2434.  
  2435. /*--------------------------------*********************---------------------------------*/
  2436. /*    
  2437.  
  2438. static functions follow. Do not modify them directly- all features can be acessed by
  2439. overriding the appropriate methods.
  2440.  
  2441. ----------------------------------------------------------------------------------------*/
  2442.  
  2443. static pascal OSErr    ZWTrackingHandler(DragTrackingMessage theMsg, WindowPtr theWindow, void* refCon,
  2444.                                     DragReference theDrag)
  2445. {
  2446.     ZWindow*    zdWindow = NULL;
  2447.     OSErr        theErr = noErr;
  2448.     
  2449.     // get the object
  2450.     
  2451.     if ( theWindow )
  2452.         zdWindow = GetZWindow( theWindow );
  2453.  
  2454.     try
  2455.     {
  2456.         FailNIL( zdWindow );
  2457.         
  2458.         zdWindow->DragDispatch( theMsg, theDrag );
  2459.     }
  2460.     catch( OSErr err )
  2461.     {
  2462.         theErr = err;
  2463.     }
  2464.     
  2465.     return theErr;
  2466. }
  2467.  
  2468.  
  2469. /*--------------------------------*********************---------------------------------*/
  2470.  
  2471. static pascal OSErr    ZWDropHandler( WindowPtr theWindow, void* refCon, DragReference theDrag )
  2472. {
  2473.     ZWindow*    zdWindow = NULL;
  2474.     OSErr        theErr = noErr;
  2475.     // get the object
  2476.     
  2477.     if ( theWindow )
  2478.         zdWindow = GetZWindow( theWindow );
  2479.  
  2480.     try
  2481.     {
  2482.         FailNIL( zdWindow );
  2483.         
  2484.         zdWindow->DropHandler( theDrag );
  2485.     }
  2486.     catch( OSErr err )
  2487.     {
  2488.         theErr = err;
  2489.         
  2490.         // if there was an error that aborted the drop, we would like to report it to the
  2491.         // user. However, this is a bad time to do it, so instead we set <gDragErr> which
  2492.         // ZApplicaiton will pick up & report next time it loops, using the Notification
  2493.         // Manager if in background.
  2494.         
  2495.         if ( err != dragNotAcceptedErr )
  2496.             gDragErr = err;
  2497.     }
  2498.     
  2499.     return theErr;
  2500. }
  2501.  
  2502. /*--------------------------------*********************---------------------------------*/
  2503.  
  2504.  
  2505.  
  2506.